Skip to content

[Session 1] 주재현 - Pythonic Code#3

Open
joojae02 wants to merge 4 commits intomainfrom
session1/주재현

Hidden character warning

The head ref may contain hidden characters: "session1/\uc8fc\uc7ac\ud604"
Open

[Session 1] 주재현 - Pythonic Code#3
joojae02 wants to merge 4 commits intomainfrom
session1/주재현

Conversation

@joojae02
Copy link
Collaborator

@joojae02 joojae02 commented Oct 9, 2025

학습 내용 요약

파이썬의 고급 기능 4가지를 학습했습니다.
컴프리헨션으로 반복문을 한 줄로 압축하는 방법, 언패킹과 제너레이터로 메모리 효율적인 데이터 처리, 매직 메서드로 클래스 커스터마이징, 데코레이터로 함수 기능 확장하는 방법을 배웠습니다.

핵심 개념

제너레이터와 이터레이터의 차이점과 활용법이 가장 중요하다고 생각합니다.
제너레이터는 yield 키워드를 사용해 메모리 효율적으로 대용량 데이터를 처리할 수 있게 해주며, 이터레이터는 __iter__()__next__() 메서드를 구현해 순회 가능한 객체를 만드는 기반이 됩니다.
특히 지연 평가(Lazy Evaluation) 개념을 이해하면 메모리 사용량을 크게 줄일 수 있습니다.

실습 예제

참고 자료

체크리스트

  • 주제에 대한 핵심 내용을 다루고 있다
  • 실습 가능한 코드 예제가 포함되어 있다
  • 마크다운 문법이 올바르게 적용되었다
  • 참고 자료 출처가 명시되어 있다

@joojae02 joojae02 self-assigned this Oct 9, 2025
@rover0811
Copy link
Member

대량의 로그 파일(100GB)을 처리해서 특정 패턴의 라인만 추출해야 한다면, 컴프리헨션/제너레이터/이터레이터 중 무엇을 선택할까요? 각각의 메모리 사용량 차이를 예상해보면 좋을 것 같아요.

# 리스트 컴프리헨션 활용
squares_comp = [i * i for i in range(10) if i % 2 == 0]
print(squares_comp) # [0, 4, 16, 36, 64]
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2중, 3중 중첩된 리스트 컴프리헨션을 작성해본 경험이 있나요? 어느 시점부터 일반 for문으로 바꾸는 것이 더 나을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

명확한 기준이 있지는 않아서 팀 규칙에 따라 작성하면 될것 같습니다.
개인적으로는 (2중 컴프리핸션 + If문) 부터 for문으로 바꾸는 편입니다.


일반적인 상황에서 List comprehension 의 동작이 유의미하게 빠르다.
아래 예제를 통해 간단하게 확인이 가능하다.
> 정확히 설명하자면 인터프리터 모드인 경우에 유의미하게 빠르다.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

자료에서 "인터프리터 모드에서 유의미하게 빠르다"고 했는데, 컴파일된 코드에서는 차이가 없을까요? 그리고 왜 컴프리헨션이 더 빠른지 내부 동작 원리를 설명할 수 있나요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cpython 과 같이 컴파일된 코드에선 차이가 없는걸로 알고 있습니다.

리스트를 생성하는 코드에서 list.append() 바이트 코드 레벨에서 성능 차이가 발생하는걸로 알고 있습니다.


# 실행 시간 측정
for_loop_time = timeit.timeit(stmt=for_loop_code, setup=setup_code, number=1)
comprehension_time = timeit.timeit(stmt=comprehension_code, setup=setup_code, number=1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1억 개의 숫자를 처리해야 한다면 리스트 컴프리헨션이 최선일까요? 제너레이터 표현식 (x**2 for x in range(100000000))과 비교했을 때 어떤 차이가 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 케이스라면 제너레이터를 쓰는게 맞을것 같습니다.
리스트 컴프리헨션은 모두 메모리에 올려서 한번에 처리해 메모리 이슈가 생길것 같습니다.

my_gen = number_generator(3)
print(next(my_gen)) # Generator starts, 1 출력
print(next(my_gen)) # 1 yielded, 2 출력
print(next(my_gen)) # 2 yielded, 3 출력
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예제의 my_gen을 한번 순회한 후 다시 사용하려면 어떻게 해야 할까요? 제너레이터가 exhausted되는 특성이 실제 코딩에서 어떤 버그를 유발할 수 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제너레이터는 재사용(reset)이 불가능한것으로 알고 있어서 다시 사용하려면 재할당이 필요할것 같습니다.
데이터 검증 같은 호출에서 exhausted 되어 예상치 못한 버그를 일으킬 수 있습니다.


#### 이터레이터 vs 이터러블
- **이터러블(Iterable)**: `__iter__()` 메서드를 가진 객체 (리스트, 튜플, 문자열 등)
- **이터레이터(Iterator)**: `__iter__()`와 `__next__()` 메서드를 모두 가진 객체
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

iter()와 next()를 구현해야 하는 이유는 뭘까요? 그냥 리스트를 반환하면 안 되는 특별한 상황이 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리스트로 반환할 경우 리스트 전체를 메모리에 올려야해서 Lazy하게 처리하기 위해 사용합니다.

- 주로 개발자가 디버깅 목적으로 사용하는, 객체를 **명확하게 식별**할 수 있는 **공식적인** 문자열 표현을 반환하는 데 사용된다. `eval(repr(obj)) == obj`가 성립하는 것을 목표로 한다.
- `__eq__(self, other)`
- `==` 연산자를 사용하여 두 객체의 **내용이 같은지** 비교할 때 호출된다.
- 이 메서드를 구현하지 않으면, 기본적으로 두 객체의 메모리 주소를 비교한다.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__eq__만 구현하고 __hash__를 구현하지 않으면 어떤 문제가 생길까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해시 불가능해서 에러가 발생합니다.
Hashable Contract 로 두 객체가 같다면, 두 객체의 해시값도 반드시 같아야 한다 때문에 그렇군요..?
처음 알았네요!

return result
return wrapper

@measure_time
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여러 데코레이터를 겹쳐서 사용할 때(@decorator1 @decorator2 @func) 실행 순서는 어떻게 될까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

func = decorator1(decorator2(func))와 동일합니다.

import time

def measure_time(func):
def wrapper(*args, **kwargs):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예제의 wrapper 함수는 원본 함수의 메타데이터(이름, docstring 등)를 잃어버려요. @functools.wraps(func)를 사용하지 않으면 어떤 문제가 생길까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사용하지 않을 경우 디버깅하는데 있어서 원본 함수가 보이지 않고 Typehint 등이 사라질 수 있습니다

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants